package com.zyy.joseata.interceptor;

import com.zyy.joseata.annotation.JoCancel;
import com.zyy.joseata.annotation.JoConfirm;
import com.zyy.joseata.annotation.JoGlobalTransactional;
import com.zyy.joseata.bo.TxClazzBO;
import com.zyy.joseata.constant.TxEventTypeConst;
import com.zyy.joseata.socket.SocketClient;
import com.zyy.joseata.util.*;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author zhangyy
 */
@Aspect
@Component
@Slf4j
@Order(-1)
public class GlobalTransInterceptor {

    @Resource
    private SocketClient socketClient;

//    @Before("@annotation(com.zyy.joseata.annotation.JoGlobalTransactional)")
//    public void beforeGlobalTransactional(){
//        log.info("JoGlobalTransactional注解拦截");
//    }

    @Around("@annotation(com.zyy.joseata.annotation.JoGlobalTransactional)")
    public Object aroundGlobalTransactional(ProceedingJoinPoint joinPoint) throws Throwable{
        log.info("JoGlobalTransactional注解 拦截 before");
        Object result = null;
        try {
            String txId = UUIdUtil.getId();

            ThreadLocalUtil.setTxId(txId);

            JoSeataContextUtil.setAttrTxId(txId);

            socketClient.send(TxEventTypeConst.GLOBAL_TX_START_EVENT);

            // 执行原本方法
            result = joinPoint.proceed();

        } catch (Throwable e) {
            log.error("全局事务完成失败",e);
            throw e;
        }finally {
            socketClient.send(TxEventTypeConst.GLOBAL_TX_COMPLETE);

            // 释放txId
            ThreadLocalUtil.removeTxId();
        }
        log.info("JoGlobalTransactional注解 around 拦截 after");
        return result;
    }

    /**
     * 获取方法上的注解
     * @param joinPoint
     * @param annotationType
     * @param <T>
     * @return
     */
    private <T extends Annotation> T getAnnotation(ProceedingJoinPoint joinPoint, Class<T> annotationType) {
        try {
            // 获取目标方法
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Method method = methodSignature.getMethod();

            // 获取方法上的注解
            return method.getAnnotation(annotationType);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 执行方法
     * @param beanClazz
     * @param methodName
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private void executeMethod(Class beanClazz,String methodName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object bean = JoSpringBeanUtil.getBean(beanClazz);
        //Class<?> beanClazz = bean.getClass();
        Method method = beanClazz.getMethod(methodName);
        method.invoke(bean);
    }

    /**
     * 获取方法名
     * @param joinPoint
     * @return
     */
    private String getMethodName(ProceedingJoinPoint joinPoint){
        String methodName= joinPoint.getSignature().getName();
        return methodName;
    }

}
